﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.Skins;
using DevExpress.LookAndFeel;
using DevExpress.UserSkins;
using DevExpress.XtraEditors;
using DevExpress.XtraCharts;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Data;

namespace RAMain
{
    public partial class Form1 : XtraForm
    {
        public class DataTransferObj : MarshalByRefObject, RADB.IDataTransfer
        {
            public static RADB.DataSetRA dataSet = new RADB.DataSetRA();

            public const int EmpManager = 1;
            public const int EmpHost = 2;
            public const int EmpWaiter = 3;
            public const int EmpCook = 4;
            public const int EmpBusBoy = 5;
            public const int tableAvailable = 1;
            public const int tableReserved = 2;
            public const int tableWaiting = 3;
            public const int tableOccupied = 4;
            public const int tableDirty = 5;
            public const int tableCleaning = 6;
            public const int orderWaiting = 1;
            public const int orderCooking = 2;
            public const int orderReady = 3;
            public const int orderCanncelled = 4;
            public const int orderDelivered = 5;

            private bool setTableStatus(int tableID, int status)
            {
                RADB.DataSetRA.TablesRow row = dataSet._Tables.FindByID(tableID);
                if (row == null)
                {
                    return false;
                }
                try
                {
                    lock (this)
                    {
                        row.Status = status;
                        Form1.commitTables(dataSet, dataSet._Tables.TableName); 
                    }
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }

            private bool setItemStatus(int itemID, int status)
            {
                RADB.DataSetRA.OrderItemsRow row = dataSet.OrderItems.FindByID(itemID);
                if (row == null)
                {
                    return false;
                }
                try
                {
                    lock (this)
                    {
                        row.Status = status;
                        Form1.commitTables(dataSet, dataSet.OrderItems.TableName); 
                    }
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }
            //Waiters
            #region Waiters
            public DataTable getWaitingTables()
            {
                RADB.DataSetRA.TablesDataTable res = new RADB.DataSetRA.TablesDataTable();
                foreach (DataRow row in dataSet._Tables.Select(string.Format("status = {0} OR status = {1}", tableWaiting, tableOccupied)))
                {
                    res.Rows.Add(row.ItemArray);
                }
                return res;
            }
            public DataTable getCategories()
            {
                return dataSet.Categories;
            }
            public DataTable getProducts()
            {
                RADB.DataSetRA.ProductsDataTable res = new RADB.DataSetRA.ProductsDataTable();

                foreach (DataRow row in dataSet.Products.Select("available = true"))
                {
                    res.Rows.Add(row.ItemArray);
                }
                return res;
            }
            public bool placeAnOrder(int WaiterID, RADB.OrderItemDTO info)
            {
                RADB.DataSetRA.OrderItemsRow row = dataSet.OrderItems.NewOrderItemsRow();

                RADB.DataSetRA.TablesRow tRow = dataSet._Tables.FindByID(info.tableID);
                if (tRow == null)
                {
                    return false;
                }                
                try
                {
                    lock (this)
                    {
                        DataRow[] sRow = dataSet.Sessions.Select(string.Format("table = {0} AND finishTime IS NULL", info.tableID));
                        if (sRow.Length == 1)
                        {
                            row.Session = (int)sRow[0]["ID"];
                        }
                        else
                        {
                            RADB.DataSetRA.SessionsRow newSRow = dataSet.Sessions.NewSessionsRow();
                            newSRow.StartTime = DateTime.Now;
                            newSRow._Table = info.tableID;

                            dataSet.Sessions.AddSessionsRow(newSRow);
                            Form1.commitTables(dataSet, dataSet.Sessions.TableName);
                            row.Session = newSRow.ID;
                        }
                        row.Product = info.productID;
                        row.Price = dataSet.Products.FindByID(info.productID).MenuPrice;
                        row.Quantity = info.quantity;
                        row.Status = orderWaiting;
                        row.PlacingWaiter = WaiterID;
                        row.PlacingTime = DateTime.Now;

                        dataSet.OrderItems.AddOrderItemsRow(row);
                        Form1.commitTables(dataSet, dataSet.OrderItems.TableName); 
                    }
                }
                catch (Exception)
                {
                    return false;
                }                
                return true;
            }
            public DataTable getReadyItems()
            {
                DataRow returnRow;
                RADB.DataSetRA.OrderItemsDataTable res = new RADB.DataSetRA.OrderItemsDataTable();
                res.DeliverWaiterColumn.ColumnName = "Table";

                foreach (DataRow row in dataSet.OrderItems.Select(string.Format("status = {0}", orderReady)))
                {
                    returnRow = res.Rows.Add(row.ItemArray);
                    returnRow["Table"] = dataSet._Tables.FindByID(dataSet.Sessions.FindByID((int)row["Session"])._Table).ID.ToString();
                }
                return res;
            }
            public bool deliverAnItem(int WaiterID, int itemID)
            {
                RADB.DataSetRA.OrderItemsRow row = dataSet.OrderItems.FindByID(itemID);
                if (row == null)
                {
                    return false;
                }
                try
                {
                    lock (this)
                    {
                        if (row.Status != orderReady)
                        {
                            return false;
                        }
                        row.Status = orderDelivered;
                        row.DeliverWaiter = WaiterID;
                        row.FinishedTime = DateTime.Now;
                        Form1.commitTables(dataSet, dataSet.OrderItems.TableName); 
                    }
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }

            public bool setTableOccupied(int tableID)
            {
                RADB.DataSetRA.TablesRow tRow = dataSet._Tables.FindByID(tableID);
                if (tRow == null || !(tRow.Status == tableWaiting || tRow.Status == tableOccupied))
                {
                    return false;
                }
                lock (this)
                {
                    return setTableStatus(tableID, tableOccupied); 
                }
            }

            public bool setTableDirty(int tableID)
            {
                lock (this)
                {
                    bool res = setTableStatus(tableID, tableDirty);
                    DataRow[] sRow = dataSet.Sessions.Select(string.Format("table = {0} AND finishTime IS NULL", tableID));
                    foreach (DataRow row in sRow)
                    {
                        dataSet.Sessions.FindByID((int)row["ID"]).FinishTime = DateTime.Now;
                        DataRow[] oRows = row.GetChildRows("FK__OrderItem__Sessi__2E1BDC42");
                        foreach (DataRow oRow in oRows)
                        {
                            if (!cancelAnOrder((int)oRow["ID"]))
                            {
                                setItemStatus((int)oRow["ID"], orderDelivered);
                            }
                        }
                    }
                    return res; 
                }
            }
            public DataTable getOrderedItems(int tableID)
            {
                RADB.DataSetRA.OrderItemsDataTable res = new RADB.DataSetRA.OrderItemsDataTable();
                DataRow[] sRow = dataSet.Sessions.Select(string.Format("table = {0} AND finishTime IS NULL", tableID));
                if (sRow.Length == 1)
                {
                    int session = (int)sRow[0]["ID"];
                    
                    DataRow[] orderedItems = dataSet.OrderItems.Select(string.Format("Session = {0}", session));
                    foreach (DataRow row in orderedItems)
                    {
                        res.Rows.Add(row.ItemArray);
                    }
                }
                return res;
            }
            public DataTable getOrderStatusList()
            {
                return dataSet.OrderStatus;
            }
            public bool cancelAnOrder(int itemID)
            {
                RADB.DataSetRA.OrderItemsRow row = dataSet.OrderItems.FindByID(itemID);
                if (row == null)
                {
                    return false;
                }
                try
                {
                    lock (this)
                    {
                        if (row.Status == orderReady || row.Status == orderDelivered || row.Status == orderCooking)
                        {
                            return false;
                        }
                        row.Status = orderCanncelled;
                        Form1.commitTables(dataSet, dataSet.OrderItems.TableName); 
                    }
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }
            #endregion

            //Host
            #region Hosts
            public DataTable getTables()
            {
                return dataSet._Tables;
            }
            public bool setTableWaiting(int tableID)
            {
                return setTableStatus(tableID, tableWaiting);
            }
            public bool reserveTable(int tableID, DateTime startTime, DateTime finishTime)
            {
                lock (this)
                {
                    RADB.DataSetRA.ReservedPeriodsRow row = dataSet.ReservedPeriods.NewReservedPeriodsRow();

                    row._Table = tableID;
                    row.StartTime = startTime;
                    row.FinishTime = finishTime;
                    try
                    {
                        dataSet.ReservedPeriods.AddReservedPeriodsRow(row);
                        Form1.commitTables(dataSet, dataSet.ReservedPeriods.TableName);
                    }
                    catch (Exception)
                    {
                        return false;
                    }

                    return true; 
                }
            } 
            #endregion

            //Busboy
            #region BusBoys
            public DataTable getDirtyTables()
            {
                RADB.DataSetRA.TablesDataTable res = new RADB.DataSetRA.TablesDataTable();
                foreach (DataRow row in dataSet._Tables.Select(string.Format("status = {0}", tableDirty)))
                {
                    res.Rows.Add(row.ItemArray);
                }
                return res;
            }
            public bool setTableCleaning(int BusBoyID, int tableID)
            {
                lock (this)
                {
                    RADB.DataSetRA.TablesRow row = dataSet._Tables.FindByID(tableID);
                    if (row == null)
                    {
                        return false;
                    }
                    try
                    {
                        row.Status = tableCleaning;
                        //update busboy cleaning this table
                        Form1.commitTables(dataSet, dataSet._Tables.TableName);
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                    return true; 
                }
            }
            public bool setTableAvailable(int tableID)
            {
                lock (this)
                {
                    return setTableStatus(tableID, tableAvailable); 
                }
            } 
            #endregion

            //cook
            #region Cooks
            public DataTable getWaitingItems()
            {
                RADB.DataSetRA.OrderItemsDataTable res = new RADB.DataSetRA.OrderItemsDataTable();

                foreach (DataRow row in dataSet.OrderItems.Select(string.Format("status = {0}", orderWaiting)))
                {
                    res.Rows.Add(row.ItemArray);
                }
                return res;
            }

            public DataTable getCookingItems()
            {
                RADB.DataSetRA.OrderItemsDataTable res = new RADB.DataSetRA.OrderItemsDataTable();

                foreach (DataRow row in dataSet.OrderItems.Select(string.Format("status = {0}", orderCooking)))
                {
                    res.Rows.Add(row.ItemArray);
                }
                return res;
            }

            public bool setItemCooking(int CookID, int itemID)
            {
                RADB.DataSetRA.OrderItemsRow row = dataSet.OrderItems.FindByID(itemID);
                if (row == null)
                {
                    return false;
                }
                try
                {
                    lock (this)
                    {
                        row.Status = orderCooking;
                        row.Cook = CookID;
                        Form1.commitTables(dataSet, dataSet.OrderItems.TableName); 
                    }
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }
            public bool notifyAnItem(int itemID)
            {
                lock (this)
                {
                    return setItemStatus(itemID, orderReady); 
                }
            } 
            #endregion

            #region Authentication
            public int login(string username, string password)
            {
                foreach (RADB.DataSetRA.EmployeesRow row in dataSet.Employees)
                {
                    if (row.EmployeeCode.ToUpper() == username.ToUpper())
                    {
                        if (row.Pass == password)
                        {
                            return row.ID;
                        }
                        else
                        {
                            return 0;
                        }
                    }
                }
                return 0;
            }
            public bool changePassword(int empId, string oldPassWord, string newPassWord)
            {
                RADB.DataSetRA.EmployeesRow row = dataSet.Employees.FindByID(empId);
                if (row != null && row.Pass == oldPassWord)
                {
                    row.Pass = newPassWord;
                    return true;
                }
                return false;
            }

            public bool isManager(int id)
            {
                RADB.DataSetRA.EmployeesRow row = dataSet.Employees.FindByID(id);
                return row != null && row.Role == EmpManager;
            }
            public bool isHost(int id)
            {
                RADB.DataSetRA.EmployeesRow row = dataSet.Employees.FindByID(id);
                return row != null && (row.Role == EmpHost || row.Role == EmpManager);
            }
            public bool isWaiter(int id)
            {
                RADB.DataSetRA.EmployeesRow row = dataSet.Employees.FindByID(id);
                return row != null && (row.Role == EmpWaiter || row.Role == EmpManager);
            }
            public bool isCook(int id)
            {
                RADB.DataSetRA.EmployeesRow row = dataSet.Employees.FindByID(id);
                return row != null && (row.Role == EmpCook || row.Role == EmpManager);
            }
            public bool isBusBoy(int id)
            {
                RADB.DataSetRA.EmployeesRow row = dataSet.Employees.FindByID(id);
                return row != null && (row.Role == EmpBusBoy || row.Role == EmpManager);
            } 
            #endregion
        }
        static private void OpenServer()
        {
            HttpChannel channel = new HttpChannel(Properties.Settings.Default.RemoteObjPort);
            ChannelServices.RegisterChannel(channel, false);


            if (Properties.Settings.Default.RemoteObjSingleTon)
            {
                RemotingConfiguration.RegisterWellKnownServiceType(typeof(DataTransferObj), Properties.Settings.Default.RemoteObjName, WellKnownObjectMode.Singleton);
            }
            else
            {
                RemotingConfiguration.RegisterWellKnownServiceType(typeof(DataTransferObj), Properties.Settings.Default.RemoteObjName, WellKnownObjectMode.SingleCall);
            }
            //RemotingConfiguration.RegisterActivatedServiceType(typeof(DataTransferObj));
        }
    }    
}
